import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from passlib.context import CryptContext
from datetime import datetime, timedelta
from config import TOKEN_EXPIRES, SECRET_KEY


# https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/
class AuthHandler:
    # bearer: a header Authorization with a value of Bearer plus a token.
    security = HTTPBearer()
    # 哈希密码和校验密码帮助类CryptContext
    pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
    secret = SECRET_KEY

    def get_password_hash(self, password):
        return self.pwd_context.hash(password)

    def verify_password(self, password, hashed_password):
        return self.pwd_context.verify(password, hashed_password)

    def encode_token(self, sub, aud=None, expires=TOKEN_EXPIRES):
        payload = {
            'exp': datetime.utcnow() + timedelta(minutes=expires),
            'iat': datetime.utcnow(),
            'sub': sub,
        }
        if aud:
            payload['aud'] = aud
        return jwt.encode(payload, self.secret, algorithm='HS256')

    def decode_token(self, token, audience=None):
        try:
            payload = jwt.decode(token, self.secret, algorithms=['HS256'], audience=audience)
            return payload['sub']
        except jwt.ExpiredSignatureError:
            raise HTTPException(status_code=401, detail='口令已经过期')
        except jwt.InvalidTokenError:
            raise HTTPException(status_code=401, detail='无效口令')

    # 类作为依赖，内部实现了__call__魔法方法
    def auth_wrapper(self, auth: HTTPAuthorizationCredentials = Security(security)):
        return self.decode_token(auth.credentials)  # 返回用户id(user_id)


if __name__ == '__main__':
    print(AuthHandler().get_password_hash('password'))

    handler = AuthHandler()
    token = handler.encode_token(21)
    print(handler.decode_token(token))

